
/**
 * @file Diag_UDSClient.c
 * @author dowson (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-08-03
 * 
 * @copyright Copyright (c) 2023
 * 
 */

#ifndef _DIAG_UDS_CLIENT_H__
#define _DIAG_UDS_CLIENT_H__

#include "stdint.h"
#include "stddef.h"
#include "SYS_Disk.h"


#define UDS_RECV_BUFSIZE 128
#define UDS_SEND_BUFSIZE 2560

#define SOLO_DATA_MAX_LEN 6
#define Diag_REQUEST_WAIT_TIME_MAX 0xfffff


#define Diag_NEG_RESP_LEN 3U
#define Diag_0X10_REQ_LEN 2U
#define Diag_0X10_RESP_LEN 6U
#define Diag_0X11_REQ_MIN_LEN 2U
#define Diag_0X11_RESP_BASE_LEN 2U
#define Diag_0X23_REQ_MIN_LEN 4U
#define Diag_0X23_RESP_BASE_LEN 1U
#define Diag_0X22_RESP_BASE_LEN 1U
#define Diag_0X27_REQ_BASE_LEN 2U
#define Diag_0X27_RESP_BASE_LEN 2U
#define Diag_0X28_REQ_BASE_LEN 3U
#define Diag_0X28_RESP_LEN 2U
#define Diag_0X2E_REQ_BASE_LEN 3U
#define Diag_0X2E_REQ_MIN_LEN 4U
#define Diag_0X2E_RESP_LEN 3U
#define Diag_0X31_REQ_MIN_LEN 4U
#define Diag_0X31_RESP_MIN_LEN 4U
#define Diag_0X34_REQ_BASE_LEN 3U
#define Diag_0X34_RESP_BASE_LEN 2U
#define Diag_0X35_REQ_BASE_LEN 3U
#define Diag_0X35_RESP_BASE_LEN 2U
#define Diag_0X36_REQ_BASE_LEN 2U
#define Diag_0X36_RESP_BASE_LEN 2U
#define Diag_0X37_REQ_BASE_LEN 1U
#define Diag_0X37_RESP_BASE_LEN 1U
#define Diag_0X3E_REQ_MIN_LEN 2U
#define Diag_0X3E_RESP_LEN 2U
#define Diag_0X85_REQ_BASE_LEN 2U
#define Diag_0X85_RESP_LEN 2U

typedef enum{
    Diag_FALSE = 0,
    Diag_TRUE = 1
}Diag_BoolType;

typedef uint8_t UDSECUReset_t;

typedef enum {
    Diag_SID_DIAGNOSTIC_SESSION_CONTROL = 0x10,
    Diag_SID_ECU_RESET = 0x11,
    Diag_SID_CLEAR_DIAGNOSTIC_INFORMATION = 0x14,
    Diag_SID_READ_DTC_INFORMATION = 0x19,
    Diag_SID_READ_DATA_BY_IDENTIFIER = 0x22,
    Diag_SID_READ_MEMORY_BY_ADDRESS = 0x23,
    Diag_SID_READ_SCALING_DATA_BY_IDENTIFIER = 0x24,
    Diag_SID_SECURITY_ACCESS = 0x27,
    Diag_SID_COMMUNICATION_CONTROL = 0x28,
    Diag_SID_READ_PERIODIC_DATA_BY_IDENTIFIER = 0x2A,
    Diag_SID_DYNAMICALLY_DEFINE_DATA_IDENTIFIER = 0x2C,
    Diag_SID_WRITE_DATA_BY_IDENTIFIER = 0x2E,
    Diag_SID_INPUT_CONTROL_BY_IDENTIFIER = 0x2F,
    Diag_SID_ROUTINE_CONTROL = 0x31,
    Diag_SID_REQUEST_DOWNLOAD = 0x34,
    Diag_SID_REQUEST_UPLOAD = 0x35,
    Diag_SID_TRANSFER_DATA = 0x36,
    Diag_SID_REQUEST_TRANSFER_EXIT = 0x37,
    Diag_SID_REQUEST_FILE_TRANSFER = 0x38,
    Diag_SID_WRITE_MEMORY_BY_ADDRESS = 0x3D,
    Diag_SID_TESTER_PRESENT = 0x3E,
    Diag_SID_ACCESS_TIMING_PARAMETER = 0x83,
    Diag_SID_SECURED_DATA_TRANSMISSION = 0x84,
    Diag_SID_CONTROL_DTC_SETTING = 0x85,
    Diag_SID_RESPONSE_ON_EVENT = 0x86,
}Diag_ServiceIdType;


typedef enum{
    Diag_MIDLE,     
    Diag_MSENDING,
    Diag_MWAIT,
    Diag_MPROCESS,
    Diag_MERROR,
    Diag_MCOMPLETE,
    Diag_MSTOP
}Diag_StateMachineType;

typedef enum {
    Diag_ERR = -1,                 // 通用错误
    Diag_OK = 0,                   // 成功
    Diag_ERR_TIMEOUT,              // 请求超时
    Diag_ERR_NEG_RESP,             // 否定响应
    Diag_ERR_DID_MISMATCH,         // 响应DID对不上期待的DID
    Diag_ERR_SID_MISMATCH,         // 请求和响应SID对不上
    Diag_ERR_SUBFUNCTION_MISMATCH, // 请求和响应SubFunction对不上
    Diag_ERR_TPORT,                // 传输层错误
    Diag_ERR_FILE_IO,              // 文件IO错误
    Diag_ERR_RESP_TOO_SHORT,       // 响应太短
    Diag_ERR_BUFSIZ,               // 缓冲器不够大
    Diag_ERR_INVALID_ARG,          // 参数不对、没发
    Diag_ERR_BUSY,                 // 正在忙、没发
    Diag_ERR_LOADING,              // 正在处理中
} Diag_ErrType;

typedef enum{
    Diag_REQ_IDEL = 0,
    Diag_REQ_TIMEOUT,
    Diag_REQ_ERR,
    Diag_REQ_RUNNING,
    Diag_REQ_DELAY,
}Diag_ClientReqStateType;



/**
 * @brief LEV_RT_
 * @addtogroup ecuReset_0x11
 */
enum Diag_ECUResetType {
    kHardReset = 1,
    kKeyOffOnReset = 2,
    kSoftReset = 3,
    kEnableRapidPowerShutDown = 4,
    kDisableRapidPowerShutDown = 5,
};

typedef uint8_t Diag_ECUReset_t;

/**
 * @addtogroup securityAccess_0x27
 */
enum Diag_SecurityAccessType {
    Diag_RequestSeed = 0x01,
    Diag_SendKey = 0x02,
};




/**
 * @addtogroup controlDTCSetting_0x85
 */
enum Diag_DTCSettingType {
    Diag_DTCSettingON = 0x01,
    Diag_DTCSettingOFF = 0x02,
};





typedef uint32_t Diag_TpAddr_t;

typedef struct Diag_TpHandle
{
    uint32_t recvId;
    uint32_t sendId;
    uint32_t (*recv)(struct Diag_TpHandle *tpHandle,void *buf, uint32_t count, Diag_TpAddr_t *ta_type);
    uint32_t (*send)(struct Diag_TpHandle *tpHandle,const void *buf, uint32_t count, Diag_TpAddr_t ta_type);
}Diag_TpHandleType;




typedef uint16_t Diag_SendDataSequence;
typedef enum{
    SOLO_TYPE = 0,
    MULTI_TYPE
}Diag_DataType;

typedef enum{
    SOLO_FRAME = 0,
    FIRST_FRAME = 1,
    CONTINUE_FRAME = 2,
    FLOW_FRAME = 3
}Diag_FrameType;

typedef enum{
    Diag_RESPONSE_POS = 10,
    Diag_RESPONSE_NEG,
    Diag_RESPONSE_ERR,
    Diag_RESPONSE_RUNNING
}Diag_ResponseType;

typedef struct{
    uint8_t FCBlockSize;
    uint8_t sendTimeMin;
}Diag_LongDataSendType;


typedef struct{
    Diag_DataType type;
    Diag_SendDataSequence Sequence; //用于表示当前为第几条分段报文
    Diag_LongDataSendType Diag_longDataFCMsg; //大数据对应的流控帧数据30接收的信息
    uint8_t FCBlockSendedSize; //连续帧当前发送记录
    uint16_t byteAddr;
} Diag_SendDataType;

typedef enum{
    UDS_VCU = 0,UDS_MCU,UDS_TBOX,UDS_BMS,UDS_BCM,UDS_OBCD,UDS_OBC,UDS_DCDC1,\
    UDS_DCDC2,UDS_IP,UDS_ABS,UDS_AVAS,UDS_EPS,UDS_EHB,UDS_EPB,UDS_AC,\
    UDS_TPMS,UDS_SRS,UDS_UNKNOW
}Diag_ECU_TYPE;

struct Diag_UDSClient_t;


typedef Diag_ErrType (*Diag_ClientCallback)(struct Diag_UDSClient_t *client);

typedef struct{
    Diag_ResponseType responseState;
    Diag_BoolType timeOutState;
    Diag_ClientCallback RecvCallBack;
} Diag_RecvDataType;

typedef struct Diag_UDSClient_t
{
    Diag_TpHandleType *TpHandle;
    uint32_t requestTimeMs;
    uint32_t maxTimeOutMs;
    uint8_t recvBuf[UDS_RECV_BUFSIZE];
    uint8_t sendBuf[UDS_SEND_BUFSIZE];
    uint16_t recvSize;
    uint16_t recvedSize;
    uint16_t sendSize;
    uint16_t sendedSize;
    Diag_SendDataType SendDataType;
    Diag_RecvDataType RecvDataType;
    Diag_ClientReqStateType ReqState;
    Diag_ServiceIdType sid;
    uint32_t ecuId;
    uint32_t responseId;
    Diag_ECU_TYPE ecuType;
}Diag_UDSClientType;


/**************** UDS Squence Send Mod ***********************/
#define Diag_PARAM_COUNT_MAX 8
#define Diag_SQUENCE_NODE_MAX 32

typedef enum{
    Diag_SQUENCE_WORKING = 0,
    Diag_SQUENCE_SUCCEED,
    Diag_SQUENCE_FAIL,
    Diag_SQUENCE_NONE
} Diag_SquenceFuncWorkingStateType;


typedef enum{
    Diag_UnknowFunc = 0,
    Diag_0X11_SendEcuResetFunc = 1,
    Diag_0X10_SendDiagSessCtrlFunc,
    Diag_0X28_SendCommCtrlFunc,
    Diag_0X3E_SendTesterPresentFunc,
    Diag_0X22_SendRDBIFunc,
    Diag_0X2E_SendWDBIFunc,
    Diag_0X31_SendRoutineCtrlFunc,
    Diag_0X34_SendRequestDownloadFunc,
    Diag_0X35_SendRequestUploadFunc,
    Diag_0X36_SendTransferDataFunc,
    Diag_0X36_SendTransferDataStreamFunc,
    Diag_0X37_SendRequestTransferExitFunc,
    Diag_0X27_SendSecurityAccessFunc,
    Diag_0X85_DTCControlFunc
}Diag_RequestServiceIDFuncType;

typedef enum{
    Diag_FUNC_ID = 0,
    Diag_PHY_ID = 1,
}Diag_FuncIdMarkType;

/**
 * @brief if you want use send many uds request but no want
 *          know right or wrong in medial,you can creat a sendding
 *          squence,this function can auto sendding command in your
 *          uds list and return final result
 */


typedef struct
{
    Diag_RequestServiceIDFuncType Diag_RequestServiceIDFunc;
    Diag_ClientReqStateType nodeState; //用于管理该项发送状态
    Diag_FuncIdMarkType FuncIdMark; //是否使用7df功能寻址标记
    Diag_ClientCallback CallBack;
    uint8_t ParamCount;
    uint32_t paramList[Diag_PARAM_COUNT_MAX]; //不同sid函数需要而外发送的参数,保存的数据或者地址所以使用32位来表示
}Diag_SquenceUDSType;

typedef struct{
    Diag_SquenceUDSType *SquenceNodeListHead;
    const uint8_t listSize;
    uint8_t currentItem;
    Diag_ErrType ret;
    Diag_UDSClientType *client;
    Diag_ECU_TYPE ecuType;
    uint32_t phyId;
    uint32_t responseId;
}Diag_SquenceUDSListType;

/**************************************************************************/



typedef uint8_t Diag_HaveRecvDataType;

typedef enum  {
    Diag_DefaultSession = 0x01,
    Diag_ProgrammingSession = 0x02,
    Diag_ExtendedDiagnostic = 0x03,
    Diag_SafetySystemDiagnostic = 0x04,
}Diag_UDSSessionType;

typedef enum  {
    Diag_EnableRxAndTx = 0,
    Diag_EnableRxAndDisableTx = 1,
    Diag_DisableRxAndEnableTx = 2,
    Diag_DisableRxAndTx = 3,
}Diag_UDSCommunicationControlType;

typedef enum  {
    Diag_NormalCommunicationMessages = 0x1,
    Diag_NetworkManagementCommunicationMessages = 0x2,
    Diag_NetworkManagementCommunicationMessagesAndNormalCommunicationMessages = 0x3,
}Diag_UDSCommunicationType;

typedef enum {
    Diag_StartRoutine = 1,
    Diag_StopRoutine = 2,
    Diag_RequestRoutineResults = 3,
}Diag_RoutineControlType;

typedef enum  {
    Diag_DtcOn = 0x01,
    Diag_DtcOff = 0x02,
}Diag_DTCModeType;



// ========================================================================
//                              Client
// ========================================================================

void Diag_ClearRequestContext(Diag_UDSClientType *client);
Diag_ErrType Diag_RequestSend(Diag_UDSClientType *client);
void Diag_RequestHandleServiceMainLoop(void);
Diag_ResponseType RequestResponseState(Diag_ServiceIdType sId,const uint8_t *data,uint8_t dataLen);
Diag_ErrType Diag_RequestCommCallBack(Diag_UDSClientType *client);
void Diag_CanIqrRecvCallBack(Diag_UDSClientType *client,uint32_t canId,uint8_t canData[8],uint8_t recvSize);
Diag_ErrType Diag_RequestSend(Diag_UDSClientType *client);

Diag_ErrType Diag_UDSSquenceListDefaultReset(Diag_SquenceUDSListType *Diag_SquenceUDSList,uint8_t beginItem);
Diag_SquenceFuncWorkingStateType Diag_UDSSquenceDoing(Diag_SquenceUDSListType *Diag_SquenceUDSList);
uint32_t Diag_KeyComputation(uint32_t Seed,Diag_ECU_TYPE ecu,uint8_t loopTimes);


Diag_ErrType Diag_0X11_SendEcuReset(Diag_UDSClientType *client,UDSECUReset_t type);
Diag_ErrType Diag_0X10_SendDiagSessCtrl(Diag_UDSClientType *client, Diag_UDSSessionType mode);
Diag_ErrType Diag_0X28_SendCommCtrl(Diag_UDSClientType *client, Diag_UDSCommunicationControlType ctrl,Diag_UDSCommunicationType comm);
Diag_ErrType Diag_0X3E_SendTesterPresent(Diag_UDSClientType *client);
Diag_ErrType Diag_0X22_SendRDBI(Diag_UDSClientType *client, const uint16_t *didList,
                     const uint16_t numDataIdentifiers);
Diag_ErrType Diag_0X2E_SendWDBI(Diag_UDSClientType *client, uint16_t dataIdentifier, const uint8_t *data,
                     uint16_t size);
Diag_ErrType Diag_0X31_SendRoutineCtrl(Diag_UDSClientType *client, Diag_RoutineControlType type,
                            uint16_t routineIdentifier, const uint8_t *data, uint16_t size);
Diag_ErrType Diag_0X34_SendRequestDownload(Diag_UDSClientType *client, uint8_t dataFormatIdentifier,
                                uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
                                size_t memorySize);
Diag_ErrType Diag_0X35_SendRequestUpload(Diag_UDSClientType *client, uint8_t dataFormatIdentifier,
                              uint8_t addressAndLengthFormatIdentifier, size_t memoryAddress,
                              size_t memorySize);
Diag_ErrType Diag_0X36_SendTransferData(Diag_UDSClientType *client, uint8_t blockSequenceCounter,
                             const uint16_t blockLength, const uint8_t *data, uint16_t size);
Diag_ErrType Diag_0X36_SendTransferDataStream(Diag_UDSClientType *client, uint8_t blockSequenceCounter,
                                   const uint16_t blockLength, tFileHead *fd);
Diag_ErrType Diag_0X37_SendRequestTransferExit(Diag_UDSClientType *client);
Diag_ErrType Diag_0X27_SendSecurityAccess(Diag_UDSClientType *client, uint8_t level, const uint8_t *data, uint16_t size);
Diag_ErrType Diag_0X85_DTCControl(Diag_UDSClientType *client,Diag_DTCModeType mode);


#endif





